#include "fyp/FypAppGui.h"

//------------------------------------------------------------------------------
// additional header includes
#include "fyp/FypApp.h"
#include "fyp/ShadowAlgorithm.h"
#include "fyp/ObjectManager.h"

#include "DXUT.h"
#include "DXUTgui.h"

//------------------------------------------------------------------------------
namespace ming
{
namespace fyp
{
	//--------------------------------------------------------------------------
	enum TFypAppGui::CONTROL_ID
	{
		ID_ALGORITHM,
		ID_SHADOWMAP_SIZE,
		ID_FPS,
		ID_DEPTH_BIAS_TEXT,
		ID_DEPTH_BIAS,
		ID_NEXT_OBJECT,
		ID_NEXT_PROJ_TEX,
		ID_CONTROL_EYE,
		ID_CONTROL_LIGHT,
		ID_LIGHT_ROTATE,
	};

	//--------------------------------------------------------------------------
	TFypAppGui::TFypAppGui(TFypApp *model, TGuiManager *guiMgr) :
		GuiImpl_t<TFypApp>(model, guiMgr, "FypApp")
	{
		mDlg->AddStatic(ID_FPS, L"Frame per second", 10, 20, 150, 20);
		mDlg->GetStatic(ID_FPS)->SetTextColor(0xf0ffff80);
		
		mDlg->AddStatic(-1, L"Shadow Algorithm", 10, 50, 100, 20);
		mDlg->AddComboBox(ID_ALGORITHM, 110, 50, 350, 20);

		mDlg->AddStatic(-1, L"Shadow Map Size", 10, 80, 100, 20);
		mDlg->AddComboBox(ID_SHADOWMAP_SIZE, 110, 80, 120, 20);

		mDlg->AddStatic(ID_DEPTH_BIAS_TEXT, L"Depth Bias", 10, 110, 100, 20);
		mDlg->AddSlider(ID_DEPTH_BIAS, 10, 140, 200, 20, 0, 200, 20);


		mDlg->AddButton(ID_NEXT_OBJECT, L"Display Next Object", 10, 520, 150, 20);
		mDlg->AddButton(ID_LIGHT_ROTATE, L"Toggle Light Rotation", 160, 520, 150, 20);
		mDlg->AddButton(ID_NEXT_PROJ_TEX, L"Display Next Projective Texture", 320, 520, 180, 20);

		mDlg->AddStatic(-1, L"Mouse Controls", 10, 560, 120, 20);
		mDlg->AddRadioButton(ID_CONTROL_EYE, 1, L"Eye", 130, 560, 50, 20, true);
		mDlg->AddRadioButton(ID_CONTROL_LIGHT, 1, L"Light", 180, 560, 50, 20);

		for(size_t i=0; i<mModel->mAlgorithms.size(); ++i)
		{
			WCHAR buf[256];
			StringCchPrintfW(buf, 256, L"%S", mModel->mAlgorithms[i]->GetDescription() );
			mDlg->GetComboBox(ID_ALGORITHM)->AddItem(buf, NULL);
		}

		for(size_t i=0; i<mModel->mShadowMapSizes.size(); ++i)
		{
			WCHAR buf[20];

			StringCchPrintfW(buf, 20, L"%d x %d", mModel->mShadowMapSizes[i], mModel->mShadowMapSizes[i]);
			mDlg->GetComboBox(ID_SHADOWMAP_SIZE)->AddItem(buf, NULL);
		}

		mDlg->GetComboBox(ID_ALGORITHM)->SetSelectedByIndex(0);
		mDlg->GetComboBox(ID_SHADOWMAP_SIZE)->SetSelectedByIndex(mModel->mCurrShadowMapSize);

		mModel->SetAlgorithm(0);

		UpdateModelDepthBias();
	}
	
	//--------------------------------------------------------------------------
	TFypAppGui::~TFypAppGui()
	{
	}

	//--------------------------------------------------------------------------
	void TFypAppGui::OnControlEvent(int controlID, CDXUTControl *control)
	{
		if(controlID == ID_SHADOWMAP_SIZE)
		{
			mModel->SetShadowMapSize( static_cast<CDXUTComboBox*>(control)->GetSelectedIndex() );
		}

		if(controlID == ID_ALGORITHM)
		{
			mModel->SetAlgorithm( static_cast<CDXUTComboBox*>(control)->GetSelectedIndex() );
		}

		if(controlID == ID_DEPTH_BIAS)
		{
			UpdateModelDepthBias();
		}

		if(controlID == ID_NEXT_OBJECT)
		{
			mModel->mObjMgr->NextCasterObject();
		}

		if(controlID == ID_NEXT_PROJ_TEX)
		{
			mModel->mObjMgr->NextProjectiveTexture();
		}

		if(controlID == ID_CONTROL_EYE)
			mModel->mActiveCam = mModel->mEyeCam;

		if(controlID == ID_CONTROL_LIGHT)
			mModel->mActiveCam = mModel->mLightCam;

		if(controlID == ID_LIGHT_ROTATE)
			mModel->mLightRotate = !mModel->mLightRotate;
	}

	//--------------------------------------------------------------------------
	void TFypAppGui::UpdateFrameRate()
	{
		WCHAR buf[32];
		StringCchPrintfW(buf, 256, L"Frame Per Second %f", DXUTGetFPS() );

		mDlg->GetStatic(ID_FPS)->SetText(buf);
	}

	//--------------------------------------------------------------------------
	void TFypAppGui::UpdateModelDepthBias()
	{
		float w = mDlg->GetSlider(ID_DEPTH_BIAS)->GetValue() / 200.0f;

		const float lowerBound = 0.00001f;
		const float upperBound = 0.002f;

		mModel->mShadowMapBias = upperBound * w + lowerBound * (1.0f - w);

		WCHAR buf[64];
		StringCchPrintfW(buf, 64, L"Depth Bias %8.6f", mModel->mShadowMapBias);
		mDlg->GetStatic(ID_DEPTH_BIAS_TEXT)->SetText(buf);
	}

	//--------------------------------------------------------------------------
}
}
